package com.vinoxm.common.api;

import feign.FeignException;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.Type;

@Log4j2
public class BaseApiClient {

    @Component
    static class FeignInterceptor implements RequestInterceptor {

        @Override
        public void apply(RequestTemplate requestTemplate) {
            String method = requestTemplate.method();
            String name = requestTemplate.feignTarget().name();
            String url = requestTemplate.feignTarget().url();
            String path = requestTemplate.path();
            log.info(String.format("Access request - Feign: %s [%s] %s%s", name, method, url, path));
        }
    }

    @Component
    static class FeignClientConfiguration {
        @Bean
        public Decoder feignDecoder(ObjectProvider<HttpMessageConverters> messageConverters) {
            return new OptionalDecoder((new ResponseEntityDecoder(new FeignResponseDecoder(new SpringDecoder(messageConverters)))));
        }
    }

    static class FeignResponseDecoder implements Decoder {

        private final SpringDecoder decoder;

        public FeignResponseDecoder(SpringDecoder decoder) {
            this.decoder = decoder;
        }

        @Override
        public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
            Object result = this.decoder.decode(response, type);
            RequestTemplate requestTemplate = response.request().requestTemplate();
            String method = requestTemplate.method();
            String name = requestTemplate.feignTarget().name();
            String path = requestTemplate.path();
            log.info(String.format("Request return - Feign: %s [%s] %s -> %s", name, method, path, result.toString()));
            return result;
        }
    }
}
